package cn.ad.server.job.adapter.persistence.job;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import cn.ad.server.job.adapter.dbaccess.AssembledCachedDataContainer;
import cn.ad.server.job.adapter.dbaccess.DbDataContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import cn.ad.server.domain.ad.AdMaterial;
import cn.ad.server.domain.ad.AdMaterialGroup;
import cn.ad.server.domain.ad.AdSize;
import cn.ad.server.domain.ad.AdSpace;
import cn.ad.server.domain.ad.AdTemplate;
import cn.ad.server.domain.ad.AdTemplateSpec;
import cn.ad.server.domain.ad.AppClass;
import cn.ad.server.domain.ad.Campaign;
import cn.ad.server.domain.ad.Creative;
import cn.ad.server.domain.ad.DayTargert;
import cn.ad.server.domain.ad.InteractionApp;
import cn.ad.server.domain.ad.InteractionRedirects;
import cn.ad.server.domain.ad.PubSite;
import cn.ad.server.domain.ad.Ratio;
import cn.ad.server.domain.ad.Strategy;
import cn.ad.server.domain.ad.StrategyGeoMap;
import cn.ad.server.job.domain.job.AdSpaceWarmUpService;
import cn.ad.server.domain.enumration.AdFormat;

@Repository
public class AdSpaceWarmUpServant implements AdSpaceWarmUpService {

	private static Logger logger = LoggerFactory.getLogger(AdSpaceWarmUpServant.class);

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, AdSpace> adSpaceValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, String> stringValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private RedisTemplate<String, String> redisTemplate;
	
	@Autowired
	private AssembledCachedDataContainer container;


	/**
	 * 非法数据和不是有效数据删除。有效数据插入
	 */
	public void warmUpAllAssociation() {
		/**
		 * adspace 和其他表 只要有一个更新，则 所有的adspace都要更新。 其他表增量更新。是否有问题。--->无影响
		 * adspace表是否可以增量更新。（防止数据库中数据没有load到redis和redis中的无效数据没有删除）
		 * 若可以：第一次全部加载。--->ok的数据进入redis。--->第二次增量加载根据时间。如有status！=1
		 * redis删除。新增则加入。（数据端应防止不更新update时间直接更改数据）
		 * --->如果redis宕机恢复。时间戳没丢（根据时间戳），丢（全部加载）。--->1.如果时间戳没有连贯。则会导致redis中有无效数据。
		 * （如：有一段数据没有更新）2.时间戳不能受执行的时间影响。
		 * 
		 */

		/**
		 * redis中所有的数据都再次更新。
		 */
		List<AdSpace> adSpaces = null;
		adSpaces = DbDataContainer.getAdspaceAll();
		if(adSpaces==null){
			return;
		}
		for (AdSpace adSpace:adSpaces) {
			try {
				if (adSpace.getStatus() == 1) {
					//long startTime = System.currentTimeMillis();
					AdSpace _adSpace = attachAdSpaceAssociation(adSpace);
					//long endTime = System.currentTimeMillis();
					//System.out.println(_adSpace.getId()+" 时间: "+(endTime-startTime));
					if (_adSpace != null) {
						upToRedis(_adSpace, true);
						container.getAdSpace().put(_adSpace.getId(), _adSpace);
					} else {// 非法数据
						upToRedis(adSpace, false);
						container.getAdSpace().remove(Long.valueOf(adSpace.getId()));
					}
				} else if (adSpace.getStatus() != 1) {
					upToRedis(adSpace, false);
					container.getAdSpace().remove(Long.valueOf(adSpace.getId()));
				}
			} catch (Exception e) {
				e.printStackTrace();
				if (adSpace != null) {
					logger.error("错误：在获取adspace_id =" + adSpace.getId() + "数据时发生错误 \n 错误信息：", e);
				}
			}
		}
	}

	@Value("${cached.redisDebug:false}")
	private boolean redisDebug;
	
	void upToRedis(AdSpace adspace,boolean operatorFlg){
		if(!redisDebug){
			return;
		}
		if(operatorFlg){			
			adSpaceValueOperations.set(adspace.toCacheKey(), adspace);
		}else{
			redisTemplate.delete(adspace.toCacheKey());
		}
	}
	
	/**
	 * 根据简单广告位对象。添附上相关联的数据。
	 * 
	 * @param adsp
	 * @return
	 */
	private AdSpace attachAdSpaceAssociation(AdSpace adsp) {
		AdSpace adSpace = adsp;

		if (adSpace == null) {
			return null;
		}

		if (adSpace.getAdFormat() == null) {
			logger.warn("非法数据 :  AdFormat 为null,在adSpace对象(id: " + adSpace.getId() + ")中");
			return null;
		}

		if (adSpace.getAdFormat() == AdFormat.AD_NATIVE) {
			if (adSpace.getAdTemplate() == null) {
				logger.warn("非法数据 :  AdTemplate为null,在adSpace原生类型对象(id: " + adSpace.getId() + ")中");
				return null;
			}
		}

		if (adSpace.getRatio() != null) {
//			Ratio ratio = DbDataContainer.mapRatio.get(adSpace.getRatio().getId());
			Ratio ratio = DbDataContainer.getRatio(adSpace.getRatio().getId());
			// Ratio ratio =
			// ratioDao.selectById(adSpace.getRatio().getId(),STATUS_VALID);
			adSpace.setRatio(ratio);
		}
		if (adSpace.getPubSite() != null) {
//			PubSite pubSite = DbDataContainer.mapPubSite.get(adSpace.getPubSite().getId());
			PubSite pubSite = DbDataContainer.getPubSite(adSpace.getPubSite().getId());
			// PubSite pubSite =
			// pubSiteDao.selectById(adSpace.getPubSite().getId(),STATUS_VALID);
			adSpace.setPubSite(pubSite);
		}

		// 默认创意
		if (adSpace.getDefaultCreativeOption() == 0) {
			adSpace.setDefaultCreative(null);
		} else {
			Creative defaultCreative = adSpace.getDefaultCreative();
			if (defaultCreative != null) {
				Creative creativeByIdFrmDB = getCreativeByIdFrmDB(defaultCreative.getId(), adSpace);
				if (creativeByIdFrmDB == null) {
					logger.warn("非法数据 :  没有正确的指定默认创意,在adSpac对象(id: " + adSpace.getId() + ")中");
				}
				adSpace.setDefaultCreative(creativeByIdFrmDB);
			} else {
				adSpace.setDefaultCreative(null);
				logger.warn("非法数据 :  没有正确的指定默认创意,在adSpac对象(id: " + adSpace.getId() + ")中");
			}
		}
		List<Strategy> strategys = getStrategyByAdSpaceIdFrmDB(adSpace.getId(), adSpace);
		adSpace.setStrategys(strategys);
		return adSpace;
	}

	/**
	 * 获取有效的Creative
	 * 
	 * @param id
	 * @param adSpace
	 * @return
	 */
	private Creative getCreativeByIdFrmDB(long id, AdSpace adSpace) {
		try {
//			Creative creative = DbDataContainer.mapCreative.get(id);
			Creative creative = DbDataContainer.getCreative(id);
			// Creative creative = creativeDao.selectById(id,STATUS_VALID);
			if (creative == null) {
				return null;
			}

			if (creative.getAdFormat() != adSpace.getAdFormat()) {
				// logger.warn( "非法数据 :
				// ("+creative.getId()+")creative.AdFormat不等于("+adSpace.getId()+")adSpace.AdFormat
				// " );
				return null;
			}

			if (creative.getAdFormat() == AdFormat.AD_NATIVE) {

				// 加载adMaterialGroups
				// List<AdMaterialGroup> adMaterialGroups =
				// adMaterialGroupDao.selectByCreativeId(creative.getId(),STATUS_VALID);
//				CopyOnWriteArrayList<AdMaterialGroup> adMaterialGroupList = DbDataContainer.mapAdMaterialGroupList.get(DbDataContainer.getKeyForMaterialGroup(creative.getId(), adSpace.getAdTemplate().getId()));
				
				List<AdMaterialGroup> adMaterialGroups = DbDataContainer.getAdMaterialGroups(creative.getId(), adSpace.getAdTemplate().getId());

				// List<AdMaterialGroup> adMaterialGroups =
				// adMaterialGroupDao.selectByCreativeIdNdTemplateId(creative.getId(),adSpace.getAdTemplate().getId(),STATUS_VALID);
				if (adMaterialGroups == null || adMaterialGroups.size() == 0) {
					// logger.warn( "非法数据 : 从数据库 根据 CreativeId
					// ("+creative.getId()+")和adSpace("+adSpace.getId()+")中TemplateId("+adSpace.getAdTemplate().getId()+")没有发现AdMaterialGroup对象");
					return null;
				}
				for (AdMaterialGroup adMaterialGroup : adMaterialGroups) {
					getDetailAdMaterialGroup(adMaterialGroup);
				}
				creative.setAdMaterialGroups(adMaterialGroups);
				// 加载adTemplate
				AdTemplate adTemplate = adSpace.getAdTemplate();
				adTemplate = getAdTemplate(adTemplate);
				if (adTemplate == null) {
					logger.warn("非法数据 : 在 原生 adSpace(id:" + adSpace.getId() + ") 没有 Template 对象");
				}
				creative.setAdTemplate(adTemplate);
			} else {
				// 加载adMaterials
//				List<AdMaterial> adMaterials = DbDataContainer.mapAdMaterialListByCreativeId
//						.get(DbDataContainer.getKeyForAdMaterial(creative.getId()));
				List<AdMaterial> adMaterials = DbDataContainer.getAdMaterials(creative.getId());
				// List<AdMaterial> adMaterials =
				// adMaterialDao.selectAllByCreativeId(creative.getId(),STATUS_VALID);
				if(adMaterials!=null){
					for (AdMaterial adMaterial : adMaterials) {
						getDetailAdMaterial(adMaterial);
					}
				}
				creative.setAdMaterials(adMaterials);
			}

			// 0 无交互 1 跳转 2 APP下载 3
			if (creative.getInteractionType() == 1) {
//				InteractionRedirects interactionRedirect = DbDataContainer.mapInteractionRedirects
//						.get(creative.getInteractionId());
				InteractionRedirects interactionRedirect = DbDataContainer.getInteractionRedirect(creative.getInteractionId());
				// InteractionRedirects interactionRedirect =
				// interactionRedirectsDao.findById(creative.getInteractionId());
				creative.setInteractionRedirects(interactionRedirect);
			} else if (creative.getInteractionType() == 2) {
//				InteractionApp interactionApp = DbDataContainer.mapInteractionApp.get(creative.getInteractionId());
				InteractionApp interactionApp = DbDataContainer.getInteractionApp(creative.getInteractionId());
				// InteractionApp interactionApp =
				// interactionAppDao.findById(creative.getInteractionId());
				if (interactionApp != null) {
					// 默认取两级
//					AppClass appClass = DbDataContainer.mapAppClass.get(interactionApp.getClassesId());
					AppClass appClass = DbDataContainer.getAppClass(interactionApp.getClassesId());
					// AppClass appClass =
					// appClassDao.findById(interactionApp.getClassesId());
					interactionApp.setAppClass(appClass);
					if (appClass != null && appClass.getParentId() != 0) {
//						AppClass parentAppClass = DbDataContainer.mapAppClass.get(appClass.getParentId());
						AppClass parentAppClass = DbDataContainer.getAppClass(appClass.getParentId());
						// AppClass parentAppClass =
						// appClassDao.findById(appClass.getParentId());
						appClass.setParentAppClass(parentAppClass);
					}
				}
				creative.setInteractionApp(interactionApp);
			}
			return creative;
		} catch (Exception e) {
			logger.error("错误: 当获取创意对象时发生错误。对应adSpace_Id为：" + adSpace.getId() + " creative_id为：" + id);
			throw e;
		}
	}

	/**
	 * 获取详细的AdMaterialGroup
	 * 
	 * @param adMaterialGroup
	 * @return
	 */
	private AdMaterialGroup getDetailAdMaterialGroup(AdMaterialGroup adMaterialGroup) {
		AdMaterial adMaterial = adMaterialGroup.getAdMaterial();
		if (adMaterial != null) {
//			adMaterial = DbDataContainer.mapAdMaterial.get(adMaterial.getId());
			adMaterial = DbDataContainer.getAdMaterial(adMaterial.getId());
			// adMaterial =
			// adMaterialDao.selectById(adMaterial.getId(),STATUS_VALID);
			getDetailAdMaterial(adMaterial);
			adMaterialGroup.setAdMaterial(adMaterial);
		} else {
			adMaterialGroup.setAdMaterial(null);
		}

		AdTemplateSpec adTemplateSpec = adMaterialGroup.getAdTemplateSpec();
		if (adTemplateSpec != null) {
//			adTemplateSpec = DbDataContainer.mapAdTemplateSpec.get(adTemplateSpec.getId());
			adTemplateSpec = DbDataContainer.getAdTemplateSpec((int)adTemplateSpec.getId());
			// adTemplateSpec =
			// adTemplateSpecDao.selectById(adTemplateSpec.getId(),
			// STATUS_VALID);
			adMaterialGroup.setAdTemplateSpec(adTemplateSpec);
		} else {
			adMaterialGroup.setAdTemplateSpec(null);
		}

		// 0 无交互 1 跳转 2 APP下载 3
		if (adMaterialGroup.getInteractionType() == 1) {
//			InteractionRedirects interactionRedirect = DbDataContainer.mapInteractionRedirects
//					.get(adMaterialGroup.getInteractionId());
			InteractionRedirects interactionRedirect = DbDataContainer.getInteractionRedirect(adMaterialGroup.getInteractionId());
			// InteractionRedirects interactionRedirect =
			// interactionRedirectsDao.findById(adMaterialGroup.getInteractionId());
			adMaterialGroup.setInteractionRedirects(interactionRedirect);
		} else if (adMaterialGroup.getInteractionType() == 2) {
			//InteractionApp interactionApp = DbDataContainer.mapInteractionApp.get(adMaterialGroup.getInteractionId());
			InteractionApp interactionApp = DbDataContainer.getInteractionApp(adMaterialGroup.getInteractionId());
			// InteractionApp interactionApp =
			// interactionAppDao.findById(adMaterialGroup.getInteractionId());
			if (interactionApp != null) {
				// 默认取两级
//				AppClass appClass = DbDataContainer.mapAppClass.get(interactionApp.getClassesId());
				AppClass appClass = DbDataContainer.getAppClass(interactionApp.getClassesId());
				// AppClass appClass =
				// appClassDao.findById(interactionApp.getClassesId());
				interactionApp.setAppClass(appClass);
				if (appClass != null && appClass.getParentId() != 0) {
//					AppClass parentAppClass = DbDataContainer.mapAppClass.get(appClass.getParentId());
					AppClass parentAppClass = DbDataContainer.getAppClass(appClass.getParentId());
					// AppClass parentAppClass =
					// appClassDao.findById(appClass.getParentId());
					appClass.setParentAppClass(parentAppClass);
				}
			}
			adMaterialGroup.setInteractionApp(interactionApp);
		}

		return adMaterialGroup;
	}

	/**
	 * 根据id获得AdTemplate
	 * 
	 * @param adTemplate
	 * @return
	 */
	private AdTemplate getAdTemplate(AdTemplate adTemplate) {
//		adTemplate = DbDataContainer.mapAdTemplate.get(adTemplate.getId());
		adTemplate = DbDataContainer.getAdTemplate(adTemplate.getId());
		// adTemplate = adTemplateDao.selectById(adTemplate.getId(),
		// STATUS_VALID);
		return adTemplate;
	}

	/**
	 * 获取详细的AdMaterial
	 * 
	 * @param adMaterial
	 * @return
	 */
	private AdMaterial getDetailAdMaterial(AdMaterial adMaterial) {
		if (adMaterial == null) {
			return null;
		}
		// adSize
		AdSize adSize = adMaterial.getAdSize();
		if (adSize != null) {
//			adSize = DbDataContainer.mapAdSize.get(adMaterial.getAdSize().getId());
			adSize = DbDataContainer.getAdSize(adMaterial.getAdSize().getId());
			// adSize =
			// adSizeDao.selectById(adMaterial.getAdSize().getId(),STATUS_VALID);
			adMaterial.setAdSize(adSize);
		}

		return adMaterial;
	}

	/**
	 * 根据广告位id获得有效的Strategy列表
	 * 
	 * @param id
	 * @param adSpace
	 * @return
	 */
	private List<Strategy> getStrategyByAdSpaceIdFrmDB(long id, AdSpace adSpace) {
		List<Strategy> strategys = new ArrayList<>();
//		List<Integer> strategyIds = DbDataContainer.mapStrategySpaceMap.get(id);
		List<Long> strategyIds = DbDataContainer.getStrategyIds(id);
		if(strategyIds==null){
			return null;
		}
		// List<Integer> strategyIds = strategyDao.selectSpaceId(id,
		// STATUS_VALID);
		for (Long strategyId : strategyIds) {
			try {
//				Strategy s = DbDataContainer.mapStrategy.get(strategyId);
				Strategy s = DbDataContainer.getStrategy(strategyId);
				// Strategy s = strategyDao.selectById(strategyId,
				// STATUS_VALID);
				if (s == null) {
					continue;
				}

				/**
				 * 订单 如果订单存在或status！=1 则这个策略无效为null
				 */
				Campaign campaign = s.getCampaign();
				if (campaign != null) {
//					Campaign _campaign = DbDataContainer.mapCampaign.get(campaign.getId());
					Campaign _campaign = DbDataContainer.getCampaign(campaign.getId());
					// Campaign _campaign =
					// campaignDao.selectById(campaign.getId(), STATUS_VALID);
					if (_campaign == null) {
						continue;
					}
					s.setCampaign(_campaign);
				}

				strategys.add(s);
			} catch (Exception e) {
				logger.error("错误: 执行strategy_Id为：" + strategyId + "的策略对象，获取订单发生错误。");
				throw e;
			}
		}

		for (Strategy strategy : strategys) {

			long strategyId = strategy.getId();

			try {	
				/**
				 * Device
				 */
				strategy.setDeviceTargert(DbDataContainer.getStrategyDeviceMapByStrategyId(strategyId));
				/**
				 * Crowd
				 */
				strategy.setCrowdTargert(DbDataContainer.getStrategyCrowdMapByStrategyId(strategyId));
				/**
				 * 地域定向
				 */
				List<Integer> countrys = new ArrayList<>();
				strategy.setGeoCountryTargert(countrys);
				List<Integer> states = new ArrayList<>();
				strategy.setGeoStateTargert(states);
				List<Integer> citys = new ArrayList<>();
				strategy.setGeoCityTargert(citys);
				List<Integer> districts = new ArrayList<>();
				strategy.setGeoDistrictTargert(districts);

//				List<StrategyGeoMap> geos = DbDataContainer.mapStrategyGeoMap.get(strategyId);
				List<StrategyGeoMap> geos = DbDataContainer.getStrategyGeoMaps(strategyId);
				// List<StrategyGeoMap> geos =
				// strategyGeoMapDao.selectGeo(strategyId, STATUS_VALID);
				if(geos!=null){
					for (StrategyGeoMap geoMap : geos) {
						int type = geoMap.getGeoType();
						int geoId = geoMap.getGeoId();
						// 0 国家 对应geo_country， 1 省/州 对应geo_state, 2 城市 对应geo_cidy, 3
						// 省份分区 对应geo_district',
						if (type == 0) {
							countrys.add(geoId);
						} else if (type == 1) {
							states.add(geoId);
						} else if (type == 2) {
							citys.add(geoId);
						} else if (type == 3) {
							districts.add(geoId);
						}
					}
				}

				/**
				 * 时间定向 当没有数据给定默认。当获取到DayTargert中全为0更改为全投
				 */
//				List<DayTargert> dayTargerts = DbDataContainer.mapStrategyDayMap.get(strategyId);
				List<DayTargert> dayTargerts = DbDataContainer.getDayTargerts(strategyId);
				// List<DayTargert> dayTargerts =
				// dayPartingDao.selectAllByStrategyId(strategyId,
				// STATUS_VALID);
				if (dayTargerts!=null&&dayTargerts.size() > 0) {
					DayTargert dayTargert = dayTargerts.get(0);

					if (dayTargert.getMonday() == 0 && dayTargert.getTuesday() == 0 && dayTargert.getWednesday() == 0
							&& dayTargert.getThursday() == 0 && dayTargert.getFriday() == 0
							&& dayTargert.getSaturday() == 0 && dayTargert.getSunday() == 0) {
						int allHours = 16777215;
						dayTargert.setMonday(allHours);
						dayTargert.setTuesday(allHours);
						dayTargert.setWednesday(allHours);
						dayTargert.setThursday(allHours);
						dayTargert.setFriday(allHours);
						dayTargert.setSaturday(allHours);
						dayTargert.setSunday(allHours);
						strategy.setDayTargert(dayTargert);
					}
					strategy.setDayTargert(dayTargert);
				} else {
					// 如果没有则默认一周这个时间段全投放
					DayTargert dayTargert = new DayTargert();
					int allHours = 16777215;
					dayTargert.setMonday(allHours);
					dayTargert.setTuesday(allHours);
					dayTargert.setWednesday(allHours);
					dayTargert.setThursday(allHours);
					dayTargert.setFriday(allHours);
					dayTargert.setSaturday(allHours);
					dayTargert.setSunday(allHours);
					strategy.setDayTargert(dayTargert);
				}

				/**
				 * 创意
				 */
//				List<Integer> creativeIds = DbDataContainer.mapStrategyCreativeMap.get(strategyId);
				List<Long> creativeIds = DbDataContainer.getCreativeIds(strategyId);
				// List<Integer> creativeIds =
				// strategyDao.selectCreativeId(strategyId, STATUS_VALID);
				List<Creative> creatives = new ArrayList<>();
				if(creativeIds!=null){
					for (Long creativeId : creativeIds) {
						Creative creative = getCreativeByIdFrmDB(creativeId, adSpace);
						if (creative != null) {
							creatives.add(creative);
						}
					}
				}
				if (creatives.size() == 0) {
//					logger.warn("非法数据 : 在adSpace(Id为：" + adSpace.getId() + ")对象下strategy(Id为：" + strategy.getId()
//							+ ")没有有效的创意");
				}
				strategy.setCreatives(creatives);
			} catch (Exception e) {
				logger.error("错误: 执行strategy_Id为：" + strategyId + "的策略对象时，发生错误。");
				throw e;
			}
		}

		return strategys;

	}
}
